#pragma once
#include <iostream>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <string>
#include <set>
#include <cstring>

enum Type
{
    Normol,
    Warning,
    Error,
    Debug
};
enum File 
{
    Screnn = 1,
    DefaultFile,
    CustomFile
};

class MyLog
{
#define DEFAULT_FILE_PATH "./log.txt"
#define DEFAULT_MODE 0664
static const int SIZE = 1024;

    typedef int w_type;
public:
    MyLog()
        :_mode(DEFAULT_MODE)//设置默认需要写入文件的路径权限,默认像显示屏打印
        ,_buffer(new char[SIZE])
        ,_PathFile(DEFAULT_FILE_PATH)
    {}
    ~MyLog()
    {
        for(auto& a : _sfd) close(a);
        delete[] _buffer;
    }

    void defaultprint(const std::string& funname,int _errno,int type = Error)
    {
        operator()(Error,"[%d-%d-%s]%s",__FILE__,__LINE__,funname.c_str(),strerror(_errno));
    } 
    void operator()(int type,const char* format,...)
    {
        GetTypeTimeStr(type);
        va_list args;
        va_start(args,format);
        int n = vsnprintf(_buffer,SIZE,format,args);
        if(n < 0)
        {
            perror("vsnprintf");
            exit(errno);
        }
        _buffer[n] = 0;
        _LogContent += '[';
        _LogContent += _buffer;
        _LogContent += ']';
         _LogContent += '\n';
        _buffer[0] = 0;
        Write();
    }

    void ChangeFilePath(w_type way,const char* pathname = DEFAULT_FILE_PATH,mode_t mode = DEFAULT_MODE)
    {
        if(way == Screnn)
        {
            _PathFile.clear();
        }
        else
        {
            _PathFile = pathname;
            _mode = mode;
        }
    }

private:
    void Write()
    {
        int fd = Getfd();
        if(write(fd,_LogContent.c_str(),_LogContent.size()) < 0)
        {
            perror("write");
            exit(errno);
        }
        //写完一条日志初始化属性
        _LogContent.clear();
        _PathFile.clear();
        _mode = DEFAULT_MODE;
        _sfd.insert(fd);//保存fd用于释放fd
    }
    int Getfd()
    {
        if(_PathFile.empty()){return 1;}
            
        int fd = open(_PathFile.c_str(),O_WRONLY|O_CREAT|O_APPEND,_mode);
        if(fd < 0)
        {
            perror("open");
            exit(errno);
        }
        return fd;
    } 

    const char* GetType(int type)
    {
        switch (type)
        {
        case Normol:
            return "Normol";
        case Warning:
            return " Warning";
        case Error:
            return "Error";
        case Debug:
            return "Debug";
        default:
            return "日志类型错误";
        }
    }

    void GetTypeTimeStr(int type)
    {
        const char * tp = GetType(type);
        time_t t = time(nullptr);
        struct tm* ctime = localtime(&t);
        int n = snprintf(_buffer,SIZE,"[%s][%d-%d-%d %d:%d:%d]",tp,
        ctime->tm_year + 1900,ctime->tm_mon + 1,ctime->tm_mday,ctime->tm_hour,ctime->tm_min,ctime->tm_sec);
        _buffer[n] = 0;
        _LogContent += _buffer;
        _buffer[0] = 0;
    }
    mode_t _mode;
    char* _buffer;
    std::string _LogContent;
    std::string _PathFile;
    std::set<int> _sfd;
};

MyLog lg;
